package com.clp.util;

import com.clp.util.exception.IllegalArrayLengthException;
import com.clp.util.exception.IllegalNumberException;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * 处理字节数据的工具类
 */
public class ByteUtil {
    /**
     * 返回从输入数组的指定位置，并往后指定长度部分的新数组
     *
     * @param bytes
     * @param start  开始位置
     * @param length 截取长度
     * @return
     */
    public static byte[] subBytes(byte[] bytes, int start, int length) {
        if (bytes.length < start + length) throw new IndexOutOfBoundsException("The intercepted length is out of bounds!");

        byte[] subBytes = new byte[length];
        int index = 0;
        while (index < length) {
            subBytes[index++] = bytes[start++];
        }
        return subBytes;
    }

    /**
     * 将一个8位字节转为8位字符
     *
     * @param bin
     * @return
     */
    public static String byteToBinString(byte bin) {
        String zero = "00000000";
        String binStr = Integer.toBinaryString(bin & 0xFF);
        if (binStr.length() < 8) {
            binStr = zero.substring(0, 8 - binStr.length()) + binStr;
        }
        return binStr;
    }

    /**
     * 将两个bytes数组拼接成一个
     *
     * @param bytes1 ：在前
     * @param bytes2 ：在后
     * @return
     */
    public static byte[] mergeTwoBytes(byte[] bytes1, byte[] bytes2) {
        if (bytes1 == null) return bytes2;
        if (bytes2 == null) return bytes1;

        byte[] bytes = new byte[bytes1.length + bytes2.length];
        for (int i = 0; i < bytes1.length; i++) bytes[i] = bytes1[i];
        for (int i = bytes1.length; i < bytes1.length + bytes2.length; i++) bytes[i] = bytes2[i - bytes1.length];
        return bytes;
    }

    /**
     * 判断2个字节数组是否相同
     */
    public static boolean isSameBytes(byte[] bytes1, byte[] bytes2) {
        if (bytes1.length != bytes2.length) return false;
        for (int i = 0; i < bytes1.length; i++) {
            if (bytes1[i] != bytes2[i]) return false;
        }
        return true;
    }

    /**
     * 将byte[2]转换为short类型的值，大端模式
     *
     * @param bytes2
     * @return
     */
    public static short bytes2ToShortBE(byte[] bytes2) {
        int bytes2Len = bytes2.length;
        if (bytes2Len != 2) throw new IllegalArrayLengthException(2, bytes2Len);
        short ret = 0;
        for (int i = 0; i < bytes2Len; i++) {
            ret <<= 8;
            ret |= (bytes2[i] & 0xFF);
        }
        return ret;
    }

    /**
     * 将byte[2]转换为short类型的值，小端模式
     */
    public static short bytes2ToShortLE(byte[] bytes2) {
        int bytes2Len = bytes2.length;
        if (bytes2Len != 2) throw new IllegalArrayLengthException(2, bytes2Len);
        short ret = 0;
        for (int i = bytes2.length - 1; i >= 0; i--) {
            ret <<= 8;
            ret |= (bytes2[i] & 0xFF);
        }
        return ret;
    }

    /**
     * 将byte[2]转换为int类型的值，小端模式
     *
     * @param bytes2
     * @return
     */
    public static int bytes2ToIntLE(byte[] bytes2) {
        int bytes2Len = bytes2.length;
        if (bytes2Len != 2) throw new IllegalArrayLengthException(2, bytes2Len);
        int ret = 0;
        for (int i = bytes2.length - 1; i >= 0; i--) {
            ret <<= 8;
            ret |= (bytes2[i] & 0xFF);
        }
        return ret;
    }

    /**
     * 将byte[2]转换为int类型的值，大端模式
     *
     * @param bytes2
     * @return
     */
    public static int bytes2ToIntBE(byte[] bytes2) {
        int bytes2Len = bytes2.length;
        if (bytes2Len != 2) throw new IllegalArrayLengthException(2, bytes2Len);
        int ret = 0;
        for (int i = 0; i < bytes2.length; i++) {
            ret <<= 8;
            ret |= (bytes2[i] & 0xFF);
        }
        return ret;
    }

    /**
     * 将byte[3]转换为int类型的值，小端模式
     */
    public static int bytes3ToIntLE(byte[] bytes3) {
        int bytes3Len = bytes3.length;
        if (bytes3Len != 3) throw new IllegalArrayLengthException(3, bytes3Len);
        int ret = 0;
        for (int i = bytes3.length - 1; i >= 0; i--) {
            ret <<= 8;
            ret |= (bytes3[i] & 0xFF);
        }
        return ret;
    }

    public static long bytes4ToLongLE(byte[] byte4) {
        int bytes3Len = byte4.length;
        if (bytes3Len != 4) throw new IllegalArrayLengthException(4, bytes3Len);
        long ret = 0;
        for (int i = byte4.length - 1; i >= 0; i--) {
            ret <<= 8;
            ret |= (byte4[i] & 0xFF);
        }
        return ret;
    }

    /**
     * 将byte[4]字节数组转换为短浮点数（小端模式）
     */
    public static float bytes4ToFloatLE(byte[] bytes4) {
        if (bytes4.length != 4) return 0;
        return ByteBuffer.wrap(bytes4).order(ByteOrder.LITTLE_ENDIAN).getFloat();
    }

    /**
     * 将short类型转换为byte[2]，（大端模式）
     *
     * @param value
     * @return
     */
    public static byte[] shortToBytes2BE(short value) {
        byte[] bytes = new byte[2];
        bytes[1] = (byte) (value & 0x00FF);
        bytes[0] = (byte) ((value >> 8) & 0x00FF);
        return bytes;
    }

    /**
     * 将short类型转换为byte[2]，（小端模式）
     *
     * @param value
     * @return
     */
    public static byte[] shortToBytes2LE(short value) {
        byte[] bytes = new byte[2];
        bytes[0] = (byte) (value & 0x00FF);
        bytes[1] = (byte) ((value >> 8) & 0x00FF);
        return bytes;
    }

    /**
     * 将int类型转换为bytes[2]，（大端模式）
     *
     * @param value
     * @return
     */
    public static byte[] intToBytes2BE(int value) {
        byte[] bytes = new byte[2];
        bytes[1] = (byte) (value & 0x000000FF);
        bytes[0] = (byte) ((value >> 8) & 0x000000FF);
        return bytes;
    }

    /**
     * 将int类型转换为bytes[2]，（小端模式）
     *
     * @param value
     * @return
     */
    public static byte[] intToBytes2LE(int value) {
        byte[] bytes = new byte[2];
        bytes[0] = (byte) (value & 0x000000FF);
        bytes[1] = (byte) ((value >> 8) & 0x000000FF);
        return bytes;
    }

    /**
     * 将int类型的低3个字节的内容转换为byte[3]，（小端模式）
     *
     * @param value
     */
    public static byte[] intToBytes3LE(int value) {
        byte[] bytes = new byte[3];
        bytes[0] = (byte) (value & 0x000000FF);
        bytes[1] = (byte) ((value >> 8) & 0x000000FF);
        bytes[2] = (byte) ((value >> 16) & 0x000000FF);
        return bytes;
    }

    /**
     * 将long类型的低4个字节的内容转换为byte[4] （小端模式）
     *
     * @param value
     * @return
     */
    public static byte[] longToBytes4LE(long value) {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) (value & 0x00000000000000FF);
        bytes[1] = (byte) ((value >> 8) & 0x000000FF);
        bytes[2] = (byte) ((value >> 16) & 0x000000FF);
        bytes[3] = (byte) ((value >> 24) & 0x000000FF);
        return bytes;
    }

    /**
     * 将短浮点数转换为byte[4]字节数组（小端模式）
     *
     * @param f
     * @return
     */
    public static byte[] floatToByte4LE(float f) {
        // 把float转换为byte[]
        int fbit = Float.floatToIntBits(f);

        byte[] b = new byte[4];
        for (int i = 0; i < 4; i++) {
            b[i] = (byte) (fbit >> (24 - i * 8));
        }

        // 翻转数组
        int len = b.length;
        // 建立一个与源数组元素类型相同的数组
        byte[] dest = new byte[len];
        // 为了防止修改源数组，将源数组拷贝一份副本
        System.arraycopy(b, 0, dest, 0, len);
        byte temp;
        // 将顺位第i个与倒数第i个交换
        for (int i = 0; i < len / 2; ++i) {
            temp = dest[i];
            dest[i] = dest[len - i - 1];
            dest[len - i - 1] = temp;
        }

        return dest;
    }

    /**
     * 字节转十六进制字符串
     * @param by
     * @param isUpperCase
     * @return
     */
    public static String byteToHexStr(byte by, boolean isUpperCase) {
        return ""
                + halfByteToChar((byte) ((by & 0xFF) >>> 4), isUpperCase)
                + halfByteToChar((byte) (by & 0x0F), isUpperCase);
    }

    /**
     * 字节数组转十六进制字符串
     * @param src
     * @return
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder builder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        String hv;
        for (int i = 0; i < src.length; i++) {
            hv = Integer.toHexString(src[i] & 0xFF).toUpperCase();
            if (hv.length() < 2) {
                builder.append(0);
            }
            builder.append(hv);
        }
        return builder.toString();
    }

    /**
     * 半字节转十六进制字符
     * @param halfByte
     * @param isUpperCase
     * @return
     */
    private static char halfByteToChar(byte halfByte, boolean isUpperCase) {
        switch (halfByte) {
            case 0:
                return '0';
            case 1:
                return '1';
            case 2:
                return '2';
            case 3:
                return '3';
            case 4:
                return '4';
            case 5:
                return '5';
            case 6:
                return '6';
            case 7:
                return '7';
            case 8:
                return '8';
            case 9:
                return '9';
            case 0x0A:
                return isUpperCase ? 'A' : 'a';
            case 0x0B:
                return isUpperCase ? 'B' : 'b';
            case 0x0C:
                return isUpperCase ? 'C' : 'c';
            case 0x0D:
                return isUpperCase ? 'D' : 'd';
            case 0x0E:
                return isUpperCase ? 'E' : 'e';
            case 0x0F:
                return isUpperCase ? 'F' : 'f';
            default:
                throw new IllegalNumberException(halfByte);
        }
    }
}
